package com.zxq.common.utils.json;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;


public class JsonTool implements IJson {

    private static JsonTool jsonTool = new JsonTool();
    private static final ObjectMapper objectMapper = new ObjectMapper();

    static {
        // 1.序列化时，跳过null属性
        // 2.序列化时，遇到空bean（无属性）时不会失败
        // 3.反序列化时，遇到未知属性（在bean上找不到对应属性）时不会失败
        // 4.不通过fields来探测（仅通过标准getter探测）
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.configure(MapperFeature.AUTO_DETECT_FIELDS, true);
        objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
        //Java时间格式转换
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(STANDARD_PATTERN);
        javaTimeModule.addSerializer(LocalDateTime.class,
                new LocalDateTimeSerializer(dateTimeFormatter));
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(dateTimeFormatter));
        objectMapper.registerModule(javaTimeModule);
    }

    private JsonTool() {

    }

    public static IJson getInstance() {
        return jsonTool;
    }

    @Override
    public String toJson(Object value) {
        try {
            return objectMapper.writeValueAsString(value);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public <T> T toObject(String json, Class<T> clazz) {
        try {
            return objectMapper.readValue(json, clazz);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public <T> T toObject(String json, TypeReference<?> valueTypeRef) {
        try {
            return (T) objectMapper.readValue(json, valueTypeRef);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Map<String, Object> convertToMap(Object fromValue) {
        return objectMapper.convertValue(fromValue, new TypeReference<Map<String, Object>>() {
        });
    }

    @Override
    public Map<String, Object> convertToMap(String json) {
        try {
            return objectMapper.readValue(
                    json,
                    new TypeReference<Map<String, Object>>() {
                    });
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public <T> T toObject(byte[] result, Class<T> clazz) {
        if (result == null || result.length == 0) {
            return null;
        }
        try {
            return objectMapper.readValue(result, clazz);
        } catch (Exception e) {
            throw new RuntimeException(
                    String.format("convert json:[%s] to object:[%s] due to error",
                            new String(result), clazz), e);
        }
    }

    @Override
    public <T> List<T> toList(String json, Class<T> clazz) {
        try {
            JavaType t = objectMapper.getTypeFactory().constructParametricType(
                    List.class, clazz);
            return objectMapper.readValue(json, t);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}
